package com.scs.application.modules.order.service.impl;

/**
 * @Description:
 */

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.BeanUtils;
import com.scs.application.core.utils.NumberUtils;
import com.scs.application.core.utils.SerialOwnerUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.enums.BasePrintBusType;
import com.scs.application.modules.base.request.PrintTemplateQueryRequest;
import com.scs.application.modules.base.service.PrintTemplateService;
import com.scs.application.modules.base.vo.PrintTemplateVO;
import com.scs.application.modules.order.dto.DeliveryDTO;
import com.scs.application.modules.order.dto.DeliveryItemDTO;
import com.scs.application.modules.order.entity.Delivery;
import com.scs.application.modules.order.entity.DeliveryItem;
import com.scs.application.modules.order.entity.PurchaseOrderItem;
import com.scs.application.modules.order.mapper.DeliveryMapper;
import com.scs.application.modules.order.mapper.PurchaseOrderItemMapper;
import com.scs.application.modules.order.service.DeliveryItemService;
import com.scs.application.modules.order.service.ICreateDelivery;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 创建发货单接口
 */
@Slf4j
@Service
@AllArgsConstructor
public class CreateDeliveryImpl extends BaseServiceImpl<DeliveryMapper, Delivery> implements ICreateDelivery {

    private final DeliveryItemService deliveryItemService;

    private final PurchaseOrderItemMapper purchaseOrderItemMapper;

    private final PrintTemplateService printTemplateService;

    @Override
    public String generateCode(String hospitalId, String po_code) {
        String code = "";
        PrintTemplateVO printTemplate = printTemplateService.findPrintTemplateVO(new PrintTemplateQueryRequest().setHospitalId(hospitalId)
                .setBusType(BasePrintBusType.DELIVERYCODE.getValue()));
        if(printTemplate != null && "1".equals(printTemplate.getConfigJson())){
            //查询采购订单对应最新发货单
            Delivery delivery = this.baseMapper.selectOne(Wrappers.<Delivery>query().eq("hospital_id", hospitalId).eq("po_code", po_code).orderByDesc("gmt_create").last("limit 1"));
            int count = 0;
            if(delivery == null || delivery.getCode().lastIndexOf("-") == -1){
                count = count + 1;
            }else{
                //截取最新生成发货单的次数+1
                count = Integer.parseInt(delivery.getCode().substring(delivery.getCode().lastIndexOf("-") + 1)) + 1;
            }
            code = po_code + "-" + count;
        } else {
            code = SerialUtils.generateCode(
                    SerialRuleConsts.ORDER_DELIVERY_CODE, SerialOwnerUtils.getHospitalOwner(hospitalId));
        }
        return code;
    }

    @Override
    public Delivery create(DeliveryDTO dto){

        Delivery delivery = new Delivery();
        BeanUtils.copyProperties(dto, delivery);

        // 1 保存发货单
        if(this.baseMapper.insert(delivery) != 1){
            throw new BusinessException("生成发货单出错.");
        }

        // 2 保存明细
        // 2.1 编辑（追加）发货明细中采购明细相关信息   类比：模拟页面上添加一行发货明细的操作；
        List<DeliveryItemDTO> deliveryItem = dto.getItems();
        List<DeliveryItem> items = Lists.<DeliveryItem>newArrayListWithExpectedSize(deliveryItem.size());
        BeanUtils.copyProperties(deliveryItem, items, DeliveryItem.class);

        Map<String, List<PurchaseOrderItem>> poItems = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query()
                .eq("po_id", dto.getPoId())).stream().collect(Collectors.groupingBy(PurchaseOrderItem::getId));

        // 采购明细添加到发货明细
        for(DeliveryItem dItem : items){
            // 2.2 校验开始
            // 校验发货数量
            PurchaseOrderItem poItem = poItems.get(dItem.getPoItemId()).get(0); // 这里可以get 0，因为分组的是id

            // 本次发货数量 > （应发（采购）数量 - 已发数量）
            if (dItem.getQty() > (poItem.getQty()-poItem.getDeliveredQty())) {
                log.warn("无法发货的明细：{}", poItem);
                throw new BusinessException(String.format("部分明细发货已达最大值，无法发货.[id]%s [name]%s ", poItem.getId(), poItem.getManufacturerName()));
            }
            // 校验必填项
            if(StringUtils.isBlank(dItem.getLot())){
                throw new BusinessException("批次-必填");
            }
            Date now = new Date();
            if(dItem.getProductionDate() == null || dItem.getProductionDate().compareTo(now) > 0  ){
                throw new BusinessException("生产日期-必填,且不能大于当前日期");
            }
            if(dItem.getExpiredDate() == null || dItem.getExpiredDate().compareTo(now) < 0 ){
                throw new BusinessException("过期日期-必填,且不能小于当前日期");
            }
            // 选填项校验
            if(dItem.getSterilizationDate() != null && dItem.getSterilizationDate().compareTo(now) > 0 ){
                throw new BusinessException("灭菌日期-选填,且不能大于当前日期");
            }

            dItem.setDeliveryId(delivery.getId()) // 追加发货id
                    .setShouldDeliveryQty(poItem.getQty())
                    .setDeliveredQty(poItem.getDeliveredQty())
                    .setOrderQty(poItem.getOrderQty())
                    .setOrderUnit(poItem.getOrderUnit())
                    .setSubtotalAmount(NumberUtils.multiplyDouble(dItem.getQty(), dItem.getPrice()))
                    .setId(null);
        }

        // 2.2 保存
        if( !deliveryItemService.saveBatch(items) ){
            throw new BusinessException("生成发货单明细出错.");
        }

        // 3 更新待发货单主表发货金额
        if(delivery != null && delivery.getId() != null){
            double totalAmount = deliveryItem.stream().mapToDouble(o -> o.getSubtotalAmount()).sum();
            this.baseMapper.update(new Delivery(), Wrappers.<Delivery>update()
                    .set("delivery_amount", totalAmount)
                    .eq("id", delivery.getId())
            );
            delivery.setDeliveryAmount(totalAmount);
        }
        return this.baseMapper.selectById(delivery.getId());
    }
}
